<html>
 <head>
  <meta charset="UTF-8">
 </head>
 <body>
  <h1 data-lake-id="Blx3h" id="Blx3h"><span data-lake-id="u082a0809" id="u082a0809">典型回答</span></h1>
  <p data-lake-id="u3d8fb2c3" id="u3d8fb2c3"><br></p>
  <p data-lake-id="u1a9e8716" id="u1a9e8716"><strong><span data-lake-id="ubb8cdd47" id="ubb8cdd47">JVM的跨代引用问题是指在Java堆内存的不同代之间存在引用关系</span></strong><span data-lake-id="u228f33e3" id="u228f33e3">，导致对象在不同代之间的引用被称为跨代引用。比如：新生代到老年代的引用，老年代到新生代的引用等。</span></p>
  <p data-lake-id="u74846b93" id="u74846b93"><span data-lake-id="ue66cd09a" id="ue66cd09a">​</span><br></p>
  <p data-lake-id="u4e17aa2c" id="u4e17aa2c"><strong><span data-lake-id="u1564fa4b" id="u1564fa4b">跨代引用会有什么问题呢？</span></strong></p>
  <p data-lake-id="u66708fde" id="u66708fde"><span data-lake-id="u9e08a3fa" id="u9e08a3fa">​</span><br></p>
  <blockquote data-lake-id="uf21df5c9" id="uf21df5c9">
   <p data-lake-id="uf48ad726" id="uf48ad726"><span data-lake-id="u9a9b9d2e" id="u9a9b9d2e">关于这个知识点，我看了网上很多资料，基本上没有哪个能解释的很清楚的，包括《深入理解Java虚拟机（第三版）》也是只说了其中的一部分，我综合了很多资料，加上自己的理解，试图把这个事讲的清楚一点。</span></p>
  </blockquote>
  <p data-lake-id="u72eabd14" id="u72eabd14"><span data-lake-id="uf86e131b" id="uf86e131b">​</span><br></p>
  <p data-lake-id="u7fa05f85" id="u7fa05f85"><span data-lake-id="u8aa69476" id="u8aa69476">首先看下面这张图：</span></p>
  <p data-lake-id="uecb1a0d4" id="uecb1a0d4"><span data-lake-id="u01e9e1dd" id="u01e9e1dd">​</span><br></p>
  <p data-lake-id="u9c866d84" id="u9c866d84"><img src="https://cdn.nlark.com/yuque/0/2023/png/5378072/1693574865035-ddb342ae-1857-47af-bce9-869d435cdd61.png?x-oss-process=image%2Fwatermark%2Ctype_d3F5LW1pY3JvaGVp%2Csize_32%2Ctext_SmF2YSA4IEd1IFA%3D%2Ccolor_FFFFFF%2Cshadow_50%2Ct_80%2Cg_se%2Cx_10%2Cy_10"></p>
  <p data-lake-id="ucc031095" id="ucc031095"><br></p>
  <p data-lake-id="u1d56e3ae" id="u1d56e3ae"><span data-lake-id="ucd8fa533" id="ucd8fa533">假如，我们现在JVM的堆是上面这种情况，那么在进行一次MinorGC（YoungGC）的时候，会从GC Root出发，然后进行可达性分析，假如当前正在进行一次Young GC，如果他发现一个对象处于老年代，那么JVM就会中断这条路径。</span></p>
  <p data-lake-id="ueea4422e" id="ueea4422e"><span data-lake-id="u11733da7" id="u11733da7">​</span><br></p>
  <p data-lake-id="u4885ccc6" id="u4885ccc6"><span data-lake-id="ud38aa0db" id="ud38aa0db">那么这时候，JVM就会认为只有A和B是可达的，就会在接下来的Young GC中把E回收掉，但是其实E是有引用的，只不过他的引用在老年代，发生了跨代引用。</span></p>
  <p data-lake-id="uf2c21da7" id="uf2c21da7"><span data-lake-id="ua6216d89" id="ua6216d89">​</span><br></p>
  <p data-lake-id="uc0382a03" id="uc0382a03"><span data-lake-id="u0a651ace" id="u0a651ace">想要解决解决这个问题，有两种简单的做法：</span></p>
  <p data-lake-id="u1f789261" id="u1f789261"><span data-lake-id="uc4bde0f5" id="uc4bde0f5">​</span><br></p>
  <p data-lake-id="u5d259b8a" id="u5d259b8a"><span data-lake-id="u9240cf6a" id="u9240cf6a">1、在做YoungGC的时候，GC Root出发后扫描到老年代对象后不中断，继续扫描和标记，把所有在年轻代的对象都标记上。</span></p>
  <p data-lake-id="ufd05dae0" id="ufd05dae0"><span data-lake-id="u62ce0517" id="u62ce0517">2、在YoungGC的实时，把老年代的所有对象也作为GC Root，进行可达性分析扫描。</span></p>
  <p data-lake-id="u73f21a6d" id="u73f21a6d"><span data-lake-id="ua1864a74" id="ua1864a74">​</span><br></p>
  <p data-lake-id="u859aeea6" id="u859aeea6"><span data-lake-id="u05bb5d12" id="u05bb5d12">以上两种做法，其实成本都太高了，甚至第一种要比第二种成本还要高，因为他不仅要扫描，还需要不断地做标记。</span></p>
  <p data-lake-id="u8dd0a7f3" id="u8dd0a7f3"><span data-lake-id="ud107d0e9" id="ud107d0e9">​</span><br></p>
  <p data-lake-id="u810e9c9f" id="u810e9c9f"><span data-lake-id="ubaa5811c" id="ubaa5811c">那么，于是就有一个好的办法出现了，那就是定义了一个全局的数据结构——</span><strong><span data-lake-id="ua3fa496f" id="ua3fa496f">Remembered Set</span></strong><span data-lake-id="ue8c022c3" id="ue8c022c3">。</span></p>
  <p data-lake-id="u9275b424" id="u9275b424"><span data-lake-id="u57dbf58d" id="u57dbf58d">​</span><br></p>
  <p data-lake-id="u38db668d" id="u38db668d"><span data-lake-id="ud91d2b73" id="ud91d2b73">Remembered Set 的主要作用是跟踪老年代对象与年轻代）对象之间的引用关系，以帮助识别老年代中存活对象。他的核心目标是减少全堆扫描的开销。老年代中的对象通常存活更长时间，因此为了回收年轻代，JVM需要知道哪些老年代对象引用了年轻代对象，以确保不会错误地回收正在被老年代引用的年轻代对象。</span></p>
  <p data-lake-id="ud5813a03" id="ud5813a03"><span data-lake-id="uad46634a" id="uad46634a">​</span><br></p>
  <p data-lake-id="ufe282bce" id="ufe282bce"><span data-lake-id="u8d628604" id="u8d628604">Remembered Set 记录了老年代对象指向年轻代对象的引用关系，此后当发生Minor GC时，垃圾回收器不需要扫描整个老年代来确定哪些对象存活。它只需扫描Remembered Set中的条目，从而减少了扫描的开销。</span></p>
  <p data-lake-id="u9ceb1c88" id="u9ceb1c88"><span data-lake-id="u08d74b63" id="u08d74b63">​</span><br></p>
  <p data-lake-id="u23723ca2" id="u23723ca2"><span data-lake-id="u1561bda5" id="u1561bda5">所以，在Remember Set中的对象也会被加入到GC Roots进行扫描：</span></p>
  <p data-lake-id="u1245e501" id="u1245e501"><span data-lake-id="u7cbe2fda" id="u7cbe2fda">​</span><br></p>
  <p data-lake-id="u7e50398e" id="u7e50398e"><img src="https://cdn.nlark.com/yuque/0/2023/png/5378072/1693575517507-db5da75e-08e3-4785-85ff-88094c1a7ae5.png?x-oss-process=image%2Fwatermark%2Ctype_d3F5LW1pY3JvaGVp%2Csize_38%2Ctext_SmF2YSA4IEd1IFA%3D%2Ccolor_FFFFFF%2Cshadow_50%2Ct_80%2Cg_se%2Cx_10%2Cy_10"></p>
  <p data-lake-id="u5eef58d5" id="u5eef58d5"><span data-lake-id="uc5d07da2" id="uc5d07da2">​</span><br></p>
  <p data-lake-id="ue70e6c5d" id="ue70e6c5d"><span data-lake-id="u1798700c" id="u1798700c">而在Remembered Set的实现中，比较常见的一种叫做Card Table。</span></p>
  <p data-lake-id="u839d50a9" id="u839d50a9"><span data-lake-id="u1bf0b24f" id="u1bf0b24f">​</span><br></p>
  <p data-lake-id="uc302bc2f" id="uc302bc2f"><span data-lake-id="u25b284d6" id="u25b284d6">以上，就是关于跨代引用的介绍，关于Card Table的具体实现，以及在CMS和G1中解决跨代引用的具体实现，我后面单独讲解。这里先占个坑。</span></p>
  <p data-lake-id="u7f3d17ae" id="u7f3d17ae"><span data-lake-id="uab2361d8" id="uab2361d8"> </span></p>
  <p data-lake-id="uf8670c43" id="uf8670c43"><span data-lake-id="u85255a79" id="u85255a79"> </span></p>
  <p data-lake-id="u7c29d5ed" id="u7c29d5ed"><span data-lake-id="u50a4ee6c" id="u50a4ee6c"> </span></p>
  <p data-lake-id="ua7b5e75e" id="ua7b5e75e"><span data-lake-id="u5328b533" id="u5328b533">​</span><br></p>
  <p data-lake-id="u1f821a3f" id="u1f821a3f"><br></p>
  <p data-lake-id="u745dcbba" id="u745dcbba"><span data-lake-id="u1f6291dd" id="u1f6291dd">​</span><br></p>
  <p data-lake-id="u08b7176f" id="u08b7176f"><span data-lake-id="u4a44af66" id="u4a44af66">​</span><br></p>
  <p data-lake-id="ud0b62a9a" id="ud0b62a9a"><span data-lake-id="u1d76d17a" id="u1d76d17a">​</span><br></p>
 </body>
</html>